using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using OpenPasteSpider.bind;
using OpenPasteSpider.projectmodel;
using Volo.Abp.Application.Dtos;
using Volo.Abp.ObjectMapping;
using Z.EntityFramework.Plus;

namespace OpenPasteSpider.servicemodel
{
    /// <summary>
    /// 
    /// </summary>
    [TypeFilter(typeof(RoleAttribute), Arguments = new object[] { "", "" })]
    public class ManageAppService : UserAppService
    {

        private ActionHelper _actionHelper;

        private IOpenPasteSpiderDbContext _dbContext;

        //private readonly IHttpClientFactory _httpClientFactory;

        private readonly ILogger<ManageAppService> _logger;

        private readonly IObjectMapper _objectMapper;

        private readonly PublicModelHelper _modelHelper;


        public ManageAppService(
            ActionHelper manageService,
            IOpenPasteSpiderDbContext dbContext,
            ILogger<ManageAppService> logger,
            IObjectMapper objectMapper,
            PublicModelHelper modelCache,
            IHttpContextAccessor httpContextAccessor
            ) : base(httpContextAccessor)
        {
            _actionHelper = manageService;
            _dbContext = dbContext;
            //_httpClientFactory = httpClientFactory;
            _logger = logger;
            _objectMapper = objectMapper;
            _modelHelper = modelCache;
        }

        /// <summary>
        /// 停止某一个正在运行的docker
        /// </summary>
        /// <param name="appid"></param>
        /// <returns></returns>
        [TypeFilter(typeof(RoleAttribute), Arguments = new object[] { "admin", "stop" })]
        [HttpPost]
        public async Task<int> ToStopApp(int appid)
        {
            //判断是否已经有一样的任务了
            await _actionHelper.ContainerStop(_dbContext, appid);
            return 1;
        }

        /// <summary>
        /// 查看某一个容器的运行日志
        /// </summary>
        /// <param name="appid"></param>
        /// <returns></returns>
        [TypeFilter(typeof(RoleAttribute), Arguments = new object[] { "root", "root" })]
        [HttpGet]
        public async Task<string> ReadAppLog(int appid)
        {
            var app = await _dbContext.AppInfo.Where(x => x.Id == appid).AsNoTracking().FirstOrDefaultAsync();
            if (app != null && app != default)
            {
                var log = await _actionHelper.ReadContainerLog(app.AppID, app.LinuxId);
                return log.message;
            }
            else
            {
                throw new PasteCodeException("当前容器没有找打，请重新同步容器，或者确认容器是否选择正确！");
            }
        }

    

        /// <summary>
        /// 远程执行 nginx -t 和 nginx -s relaod
        /// </summary>
        /// <param name="linuxid"></param>
        /// <returns></returns>
        /// <exception cref="PasteCodeException"></exception>
        [HttpPost]
        [TypeFilter(typeof(RoleAttribute), Arguments = new object[] { "root", "root" })]
        public async Task<string> NginxReload(int linuxid)
        {
            var result = await _actionHelper.RunCommandAsync("nginx -t && nginx -s reload", linuxid);
            return result.msg;

        }


        /// <summary>
        /// 构建镜像 镜像需要存储在哪里 是否升级这个服务的某一个环境
        /// </summary>
        /// <param name="serviceid"></param>
        /// <param name="storeid">构建存放仓储</param>
        /// <param name="modelid">非0则构建后自动升级</param>
        /// <returns></returns>
        [HttpPost]
        [TypeFilter(typeof(RoleAttribute), Arguments = new object[] { "image", "build" })]
        public async Task<int> BuildImage(int serviceid = 0, int storeid = 0, int modelid = 0)
        {
            //if (storeid == 0)
            //{
            //    throw new PasteException("仓库ID必须传，请重新确认！");
            //}
            var autoupdate = false;
            if (modelid != 0)
            {
                autoupdate = true;
                if (serviceid == 0)
                {
                    var modeldto = await _modelHelper.ItemModelInfoAsync(modelid, _dbContext);
                    serviceid = modeldto.Service.Id;
                }
            }
            if (serviceid == 0)
            {
                throw new PasteCodeException("服务ID必须不为0，请重新输入！");
            }
            var userid = base.ReadLoginUserId();
            //判断是否已经有一样的任务了
            //如果构建后要自动升级 则需要指定环境
            await _actionHelper.ImageBuild(_dbContext, serviceid, storeid, modelid, autoupdate);
            return 1;
        }

        /// <summary>
        /// 构建镜像并升级多个环境
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        /// <exception cref="PasteCodeException"></exception>
        [HttpPost]
        public async Task<string> BuildAndUpdate(InputBuildUpdate input)
        {

            //storeid models serviceid
            if (input.serviceid == 0)
            {
                throw new PasteCodeException("服务ID不能为0，必须选定一个服务作为操作对象!");
            }

            var userid = base.ReadLoginUserId();

            await _actionHelper.ImageBuild(_dbContext, input.serviceid, input.storeid, 0, true, input.models, "");

            return "构建升级命令已经提交，请前往任务列表查阅!";
        }

        /// <summary>
        /// 升级一个服务
        /// </summary>
        /// <param name="modelid"></param>
        /// <param name="version">指定一个版本</param>
        /// <param name="num">升级多少个</param>
        [HttpPost]
        [TypeFilter(typeof(RoleAttribute), Arguments = new object[] { "service", "update" })]
        public async Task<int> ServiceUpdate(int modelid, int version = 0, int num = 0)
        {
            //判断是否已经有一样的任务了

            //_modelHelper.PlanAgain(_model: OrderModel.update,);

            await _actionHelper.ModelUpdate(_dbContext, modelid, version, num);

            return 1;
        }


        /// <summary>
        /// 读取镜像列表
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<dynamic> ReadImageList(InputSearchImage input)
        {

            var datalist = new PagedResultDto<dynamic>();

            var search = _dbContext.BindServiceImage.Where(x => 1 == 1)
                .WhereIf(input.serviceid != 0, x => x.ServiceId == input.serviceid)
                .WhereIf(input.storeid != 0, x => x.StoreId == input.storeid);

            datalist.TotalCount = await search.CountAsync();

            var query = await (from bind in search
                               join b in _dbContext.ServiceInfo on bind.ServiceId equals b.Id into aaa
                               from service in aaa.DefaultIfEmpty()
                               select new
                               {
                                   ServiceName = service.Name,
                                   ServiceId = bind.ServiceId,
                                   ServiceCode = service.Code,
                                   BuildState = bind.BuildState,
                                   CreateDate = bind.CreateDate,
                                   Id = bind.Id,
                                   ImageDigest = bind.ImageDigest,
                                   IsEnable = bind.IsEnable,
                                   Version = bind.Version,
                                   StoreName = ""
                               }).OrderByDescending(x => x.Id).Page(input.page, input.size).ToListAsync();


            datalist.Items = query;

            return datalist;

        }

        /// <summary>
        /// 执行docker stats --no-stream读取列表
        /// </summary>
        /// <param name="linuxid"></param>
        /// <returns></returns>
        [HttpGet]
        public async Task<dynamic> ExecDockerStats(int linuxid)
        {
            //var backinfo = RunOnceCommand("docker stats --no-stream --format \"{\\\"container\\\":\\\"{{ .Name }}\\\",\\\"memory\\\":\\\"{{ .MemUsage }}\\\",\\\"cpu\\\":\\\"{{ .CPUPerc }}\\\",\\\"pids\\\":\\\"{{ .PIDs }}\\\",\\\"net\\\":\\\"{{ .NetIO }}\\\"}\"", linuxid);
            var result = await _actionHelper.RunCommandAsync("docker stats --no-stream --format \"{\\\"name\\\":\\\"{{ .Name }}\\\",\\\"memory\\\":\\\"{{ .MemUsage }}\\\",\\\"cpu\\\":\\\"{{ .CPUPerc }}\\\",\\\"pids\\\":\\\"{{ .PIDs }}\\\",\\\"net\\\":\\\"{{ .NetIO }}\\\"}\"", linuxid);
            if (result.ok)
            {
                return result.msg;
            }
            else
            {
                _logger.LogError(result.msg);
                throw new PasteCodeException("执行命令异常!");
            }
        }

        /// <summary>
        /// docker images
        /// </summary>
        /// <param name="linuxid"></param>
        /// <returns></returns>
        [HttpGet]
        public async Task<dynamic> ExecDockerImages(int linuxid)
        {
            var result = await _actionHelper.RunCommandAsync("docker images --format \"{\\\"name\\\":\\\"{{.Repository}}\\\",\\\"tag\\\":\\\"{{.Tag}}\\\",\\\"id\\\":\\\"{{.ID}}\\\",\\\"size\\\":\\\"{{.Size}}\\\",\\\"create\\\":\\\"{{.CreatedAt}}\\\"}\"", linuxid);
            if (result.ok)
            {
                return result.msg;
            }
            else
            {
                _logger.LogError(result.msg);
                throw new PasteCodeException("执行命令异常!");
            }
        }

        /// <summary>
        /// docker rmi name:tag
        /// </summary>
        /// <param name="linuxid"></param>
        /// <param name="name"></param>
        /// <param name="tag"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<string> ExecDockerRmiByName(int linuxid, string name, string tag = "latest")
        {
            var result = await _actionHelper.RunCommandAsync($"docker rmi {name}:{tag}", linuxid);
            if (result.ok)
            {
                return "删除镜像成功！";
            }
            else
            {
                _logger.LogError(result.msg);
                throw new PasteCodeException("执行命令异常!");
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="linuxid"></param>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<string> ExecDockerRmiById(int linuxid, string id)
        {


            if (id.Length != 12)
            {
                throw new PasteCodeException("镜像ID长度不符!应该是一串12个长度的字符串");
            }
            //cong appinfo中读取 是否删除
            var find = _dbContext.AppInfo.Where(x => x.AppID == id).FirstOrDefault();

            var result = await _actionHelper.RunCommandAsync($"docker rmi {id}", linuxid);
            if (result.ok)
            {

                if (find != null && find != default)
                {
                    find.StateCode = RunState.delete;
                    await _dbContext.SaveChangesAsync();
                }

                return "删除镜像成功！";
            }
            else
            {
                _logger.LogError(result.msg);
                throw new PasteCodeException("执行命令异常!");
            }
        }

        /// <summary>
        /// 读取服务器的内存信息
        /// </summary>
        /// <param name="linuxid"></param>
        /// <returns></returns>
        [HttpGet]
        public async Task<dynamic> ReadLinuxMemory(int linuxid)
        {
            var result = await _actionHelper.ReadLinuxMemoryAsync(linuxid);// ("docker ps -a --format \"{\\\"id\\\":\\\"{{.ID}}\\\",\\\"name\\\":\\\"{{.Names}}\\\",\\\"image\\\":\\\"{{.Image}}\\\",\\\"status\\\":\\\"{{.Status}}\\\",\\\"port\\\":\\\"{{.Ports}}\\\"}\"", linuxid);
            return result;
        }


        /// <summary>
        /// 清理服务器缓存
        /// </summary>
        /// <param name="linuxid"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<dynamic> CleanLinuxMemory(int linuxid)
        {
           await _actionHelper.RunCommandAsync("echo 1 > /proc/sys/vm/drop_caches", linuxid);

            var result = await _actionHelper.ReadLinuxMemoryAsync(linuxid);// ("docker ps -a --format \"{\\\"id\\\":\\\"{{.ID}}\\\",\\\"name\\\":\\\"{{.Names}}\\\",\\\"image\\\":\\\"{{.Image}}\\\",\\\"status\\\":\\\"{{.Status}}\\\",\\\"port\\\":\\\"{{.Ports}}\\\"}\"", linuxid);
            return result;
        }


        /// <summary>
        /// docker ps
        /// </summary>
        /// <param name="linuxid"></param>
        /// <returns></returns>
        [HttpGet]
        public async Task<dynamic> ExecDockerPs(int linuxid)
        {
            var result = await _actionHelper.RunCommandAsync("docker ps -a --format \"{\\\"id\\\":\\\"{{.ID}}\\\",\\\"name\\\":\\\"{{.Names}}\\\",\\\"image\\\":\\\"{{.Image}}\\\",\\\"status\\\":\\\"{{.Status}}\\\",\\\"port\\\":\\\"{{.Ports}}\\\"}\"", linuxid);
            if (result.ok)
            {
                return result.msg;
            }
            else
            {
                _logger.LogError(result.msg);
                throw new PasteCodeException("执行命令异常!");
            }
        }

        /// <summary>
        /// 把现有的container添加到AppInfo中
        /// </summary>
        /// <param name="linuxid"></param>
        [HttpPost]
        [TypeFilter(typeof(RoleAttribute), Arguments = new object[] { "admin", "async" })]
        public async Task<int> UpdateLinuxContainer(int linuxid)
        {
            var read = await _actionHelper.ReadDockerRunningAsync(linuxid);
            if (read != null && read.Count > 0)
            {
                var dicapps = new List<string>();
                var apps = await _dbContext.AppInfo.Where(x => x.LinuxId == linuxid).AsNoTracking().ToListAsync();
                if (apps != null && apps.Count > 0)
                {
                    dicapps = apps.Select(x => x.AppID).Distinct().ToList();
                }
                if (dicapps == null)
                {
                    dicapps = new List<string>();
                }
                var findadd = false;
                foreach (var item in read)
                {
                    if (!String.IsNullOrEmpty(item.container))
                    {
                        if (!dicapps.Contains(item.appid))
                        {
                            var one = new AppInfo();
                            one.Address = "";
                            one.AppID = item.appid;
                            one.CreateDate = DateTime.Now;
                            one.LinuxId = linuxid;
                            one.ModelId = 0;
                            one.Name = item.container;
                            one.OutPort = item.ports;
                            one.ProjectId = 0;
                            one.ServiceId = 0;
                            one.StateCode = RunState.running;
                            one.Version = 0;
                            _dbContext.Add(one);
                            findadd = true;
                        }
                    }
                }
                if (findadd)
                {
                    await _dbContext.SaveChangesAsync();
                }
            }
            return 1;
        }



        /// <summary>
        /// 读取案例模板
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        [HttpGet]
        public string ReadTemplateBody(string index)
        {
            if (System.IO.File.Exists($"template/{index}.txt"))
            {
                var body = System.IO.File.ReadAllText($"template/{index}.txt"); //CreateDto.cshtml
                return body;
            }
            else
            {
                throw new PasteCodeException("请求的模板不存在");
            }
        }

        /// <summary>
        /// 伸缩 扩容 缩减 增加运行 减少运行
        /// </summary>
        /// <param name="modelid"></param>
        /// <param name="num">大于0或者小于0</param>
        /// <param name="linuxid"></param>
        /// <returns></returns>
        [HttpPost]
        [TypeFilter(typeof(RoleAttribute), Arguments = new object[] { "service", "resize" })]
        public async Task<int> ResizeApp(int modelid, int num, int linuxid)
        {
            if (num == 0)
            {
                throw new PasteCodeException("数量不能为0 ，请重新输入");
            }

            if (linuxid == 0)
            {
                throw new PasteCodeException("需要选定服务器，请选择服务器后再操作！");
            }

            var finalynum = 0;

            var model = _dbContext.ModelInfo.Where(x => x.Id == modelid).Include(x => x.Service).AsNoTracking().FirstOrDefault();
            if (model == null || model == default)
            {
                throw new PasteCodeException("环境信息没有找到，请重试！");
            }

            var bind = _dbContext.BindModelLinux.Where(x => x.LinuxId == linuxid && x.ModelId == modelid).AsNoTracking().FirstOrDefault();
            if (bind == null || bind == default)
            {
                var one = new BindModelLinux();
                one.IsEnable = true;
                one.LimitMaxNum = 10;
                one.LimitMinNum = 1;
                one.LinuxId = linuxid;
                one.ModelId = modelid;
                one.Weight = 100;
                one.ServiceId = model.Service.Id;
                one.ModelCode = model.Code;
                _dbContext.Add(one);
                await _dbContext.SaveChangesAsync();
            }

            if (num > 0)
            {
                finalynum = await _actionHelper.AddRunAppAsync(_dbContext, modelid, num, linuxid);
            }
            else
            {
                //未完待续。。。 。。 。
                finalynum = await _actionHelper.RemoveRunApp(_dbContext, modelid, Math.Abs(0 - num), linuxid);
            }

            return finalynum;
        }

        /// <summary>
        /// 查看某一个项目的所有服务
        /// </summary>
        /// <param name="projectid"></param>
        /// <returns></returns>
        [HttpGet]
        [TypeFilter(typeof(RoleAttribute), Arguments = new object[] { "data", "view" })]
        public async Task<List<ServiceInfoListDto>> ReadService(int projectid)
        {
            var services = await _dbContext.ServiceInfo.Where(x => x.Project.Id == projectid).AsNoTracking().ToListAsync();
            if (services != null && services.Count > 0)
            {
                return _objectMapper.Map<List<ServiceInfo>, List<ServiceInfoListDto>>(services);
            }
            else
            {
                throw new PasteCodeException("没有找到这个项目的服务，请先创建服务!");
            }
        }

        /// <summary>
        /// 查看某一个服务的环境列表
        /// </summary>
        /// <param name="serviceid"></param>
        /// <returns></returns>
        [HttpGet]
        [TypeFilter(typeof(RoleAttribute), Arguments = new object[] { "data", "view" })]
        public async Task<List<ModelInfoListDto>> ReadModel(int serviceid)
        {

            var models = await _dbContext.ModelInfo.Where(x => x.Service.Id == serviceid).AsNoTracking().ToListAsync();
            if (models != null && models.Count > 0)
            {
                return _objectMapper.Map<List<ModelInfo>, List<ModelInfoListDto>>(models);
            }
            else
            {
                throw new PasteCodeException("当前服务下没有环境信息");
            }
        }

        /// <summary>
        /// 停止一个容器 并删除他
        /// </summary>
        /// <param name="id">容器ID String</param>
        /// <returns></returns>
        [HttpPost]
        public async Task<string> AppStop(string id)
        {
            //找到这个appinfo 然后执行停止的动作
            var item = await _dbContext.AppInfo.Where(x => x.AppID == id).AsNoTracking().FirstOrDefaultAsync();
            if (item == null || item == default)
            {
                throw new PasteCodeException("容器不存在！");
            }
            await _actionHelper.ContainerStop(_dbContext, item.Id);
            return $"已经提交对app:{item.Name}的停止任务，可前往任务列表查看";
        }

        /// <summary>
        /// 重启一个容器
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<string> AppRestart(string id)
        {
            //找到这个appinfo 然后执行停止的动作
            var item = await _dbContext.AppInfo.Where(x => x.AppID == id).AsNoTracking().FirstOrDefaultAsync();
            if (item == null || item == default)
            {
                throw new PasteCodeException("容器不存在！");
            }
            await _actionHelper.ContainerRestart(_dbContext, item.Id);
            return $"已经提交对app:{item.Name}的停止任务，可前往任务列表查看";
        }

        /// <summary>
        /// 刷新一个容器的状态
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<string> AppRefush(string id)
        {

            //找到这个appinfo 然后执行停止的动作
            var item = await _dbContext.AppInfo.Where(x => x.AppID == id).FirstOrDefaultAsync();
            if (item == null || item == default)
            {
                throw new PasteCodeException("容器不存在！");
            }

            var runinfo = await _actionHelper.GetDockerInspect(id, item.LinuxId);

            if (runinfo != null)
            {
                if (String.IsNullOrEmpty(item.Address) || item.Address != runinfo.IPAddress)
                {
                    item.Address = runinfo.IPAddress;
                }
                if (String.IsNullOrEmpty(item.OutPort) || item.OutPort != $"{runinfo.HostPort}")
                {
                    item.OutPort = $"{runinfo.HostPort}";
                }

                if (runinfo.Status == "running")
                {
                    if (item.StateCode != RunState.running)
                    {
                        item.StateCode = RunState.running;
                    }
                }
                else
                {
                    item.StateCode = RunState.stop;
                }
                await _dbContext.SaveChangesAsync();
            }
            else
            {
                item.StateCode = RunState.delete;
                await _dbContext.SaveChangesAsync();
            }

            return $"已经提交对app:{item.Name}的停止任务，可前往任务列表查看";
        }


        /// <summary>
        /// 远程执行删除
        /// </summary>
        /// <param name="id"></param>
        /// <param name="linuxid"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<string> AppDelete(string id, int linuxid)
        {

            //找到这个appinfo 然后执行停止的动作
            var item = await _dbContext.AppInfo.Where(x => x.AppID == id).AsNoTracking().FirstOrDefaultAsync();
            if (item == null || item == default)
            {
                //必须是非系统中的 而且停止了的

                //当前状态必须要停止的！
                //_actionHelper.GetDockerInspect();哪一个服务器的
                var info = await _actionHelper.GetDockerInspect(id, linuxid);
                if (info.Status == "exited" || info.Status == "created")
                {
                    var actionresult = await _actionHelper.RunCommandAsync($"docker rm {id}", linuxid);
                    if (actionresult.ok)
                    {
                        return $"删除成功！ 执行返回:{actionresult.msg}";
                    }
                    else
                    {
                        return $"删除失败！ 执行返回:{actionresult.msg}";
                    }
                }
                else
                {
                    return $"为了防止误删除，只有停止状态的容器才能删除！";
                }

            }
            else
            {
                return $"系统项目中的容器的删除，请使用停止并删除，因为系统要进行相关的配置变更！";
            }

            //return $"已经提交对app:{item.Name}的停止任务，可前往任务列表查看";
        }


        /// <summary>
        /// 换取某一个环境的运行分布分布在哪些服务器上
        /// </summary>
        /// <param name="modelid"></param>
        /// <returns></returns>
        [HttpGet]
        [TypeFilter(typeof(RoleAttribute), Arguments = new object[] { "data", "view" })]
        public async Task<List<OutputRunList>> ReadModelRunLinux(int modelid)
        {
            var list = await (from bind in _dbContext.BindModelLinux.Where(x => x.ModelId == modelid)
                              join b in _dbContext.LinuxInfo.Where(x => 1 == 1) on bind.LinuxId equals b.Id into abc
                              from bbc in abc.DefaultIfEmpty()
                              select new OutputRunList
                              {
                                  id = bind.Id,
                                  gname = bbc.SlaveName,
                                  name = bbc.Name,
                                  minnum = bind.LimitMinNum,
                                  maxnum = bind.LimitMaxNum,
                                  runnum = 0,
                                  linuxid = bbc.Id,
                                  isenable = true
                              }
                        ).ToListAsync();

            var runlist = await _dbContext.AppInfo.Where(x => x.ModelId == modelid && x.StateCode == RunState.running).Select(x => new
            {
                linuxid = x.LinuxId
            }).AsNoTracking().ToListAsync();
            if (runlist != null && runlist.Count > 0)
            {
                foreach (var item in list)
                {
                    item.runnum = runlist.Where(x => x.linuxid == item.linuxid).Count();
                }
            }

            var linuxs = await _dbContext.LinuxInfo.Where(x => x.IsEnable).AsNoTracking().ToListAsync();
            if (linuxs != null && linuxs.Count > 0)
            {
                if (list == null) { list = new List<OutputRunList>(); }
                foreach (var item in linuxs)
                {
                    var find = list.Where(x => x.linuxid == item.Id).FirstOrDefault();
                    if (find == null || find == default)
                    {
                        list.Add(new OutputRunList()
                        {
                            id = 0,
                            gname = item.SlaveName,
                            isenable = false,
                            linuxid = item.Id,
                            maxnum = 10,
                            minnum = 1,
                            name = item.Name,
                            runnum = 0
                        });
                    }
                }
            }


            return list;
        }


        /// <summary>
        /// 按页查询对于环境Model的服务器列表
        /// </summary>
        /// <param name="modelid"></param>
        /// <param name="page"></param>
        /// <param name="size"></param>
        /// <returns></returns>
        [HttpGet]
        [TypeFilter(typeof(RoleAttribute), Arguments = new object[] { "data", "view" })]
        public async Task<PagedResultDto<OutputRunList>> ReadLinuxForModelBind(int modelid, int page = 1, int size = 20)
        {
            var datalist = new PagedResultDto<OutputRunList>();

            var list = new List<OutputRunList>();
            var query = _dbContext.LinuxInfo.Where(x => x.IsEnable);
            datalist.TotalCount = await query.CountAsync();
            var linuxs = await query.OrderBy(x => x.Id).Page(page, size).AsNoTracking().ToListAsync();
            if (linuxs != null && linuxs.Count > 0)
            {
                if (list == null) { list = new List<OutputRunList>(); }
                foreach (var item in linuxs)
                {
                    var find = list.Where(x => x.linuxid == item.Id).FirstOrDefault();
                    if (find == null || find == default)
                    {
                        list.Add(new OutputRunList()
                        {
                            id = 0,
                            gname = item.SlaveName,
                            isenable = false,
                            linuxid = item.Id,
                            maxnum = 10,
                            minnum = 1,
                            name = item.Name,
                            runnum = 0
                        });
                    }
                }
            }

            var datalinuxids = list.Select(x => x.linuxid).ToList();

            var listbind = await (from bind in _dbContext.BindModelLinux.Where(x => x.ModelId == modelid)
                                  join b in _dbContext.LinuxInfo.Where(x => datalinuxids.Contains(x.Id)) on bind.LinuxId equals b.Id into abc
                                  from bbc in abc.DefaultIfEmpty()
                                  select new OutputRunList
                                  {
                                      id = bind.Id,
                                      gname = bbc.SlaveName,
                                      name = bbc.Name,
                                      minnum = bind.LimitMinNum,
                                      maxnum = bind.LimitMaxNum,
                                      runnum = 0,
                                      linuxid = bbc.Id,
                                      isenable = bind.IsEnable
                                  }
                        ).ToListAsync();

            var runlist = await _dbContext.AppInfo.Where(x => x.ModelId == modelid && x.StateCode == RunState.running).Select(x => new
            {
                linuxid = x.LinuxId
            }).AsNoTracking().ToListAsync();
            if (runlist != null && runlist.Count > 0)
            {
                foreach (var item in listbind)
                {
                    item.runnum = runlist.Where(x => x.linuxid == item.linuxid).Count();
                }
            }

            foreach (var item in list)
            {
                var find = listbind.Where(x => x.linuxid == item.linuxid).FirstOrDefault();
                if (find != null && find != default)
                {
                    item.id = find.id;
                    item.runnum = find.runnum;
                    item.isenable = find.isenable;
                    item.maxnum = find.maxnum;
                    item.minnum = find.minnum;
                }
            }

            datalist.Items = list;

            return datalist;
        }




        /// <summary>
        /// 绑定环境和服务器的关系，就是某一个服务的某个环境运行在哪些服务器上
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost]
        [TypeFilter(typeof(RoleAttribute), Arguments = new object[] { "data", "view" })]
        public async Task<int> BindLinuxModel(InputLinuxBindModel input)
        {
            var model = _dbContext.ModelInfo.Where(x => x.Id == input.modelid).Include(x => x.Service).AsNoTracking().FirstOrDefault();
            if (model == null || model == default)
            {
                throw new PasteCodeException("环境信息没有找打，请重试");
            }

            var bind = await _dbContext.BindModelLinux.Where(x => x.LinuxId == input.linuxid && x.ModelId == input.modelid).FirstOrDefaultAsync();
            if (bind == null || bind == default)
            {
                if (input.isenable)
                {
                    //新增一个
                    var one = new BindModelLinux();
                    one.IsEnable = input.isenable;
                    one.LimitMaxNum = input.maxnum;
                    one.LimitMinNum = input.minnum;
                    one.LinuxId = input.linuxid;
                    one.ModelId = input.modelid;
                    one.Weight = 100;
                    one.ServiceId = model.Service.Id;
                    one.ModelCode = model.Code;
                    _dbContext.Add(one);
                    await _dbContext.SaveChangesAsync();
                    if (one.LimitMinNum > 0)
                    {
                        await _actionHelper.AddRunAppAsync(_dbContext, input.modelid, input.minnum, input.linuxid);
                    }
                    //是否扩容
                }
            }
            else
            {
                //更新一个
                //是否需要缩减或者扩展
                if (input.isenable != bind.IsEnable)
                {
                    bind.IsEnable = input.isenable;
                }
                bind.LimitMinNum = input.minnum;
                bind.LimitMaxNum = input.maxnum;
                await _dbContext.SaveChangesAsync();
                //计算是否要进行伸缩的任务添加

            }

            return 1;
        }


        /// <summary>
        /// 按照条件查询运行的appinfo container
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost]
        [TypeFilter(typeof(RoleAttribute), Arguments = new object[] { "", "" })]
        public async Task<dynamic> ReadAppInfo(InputSearchApp input)
        {

            var datalist = new PagedResultDto<dynamic>();

            var query = _dbContext.AppInfo.Where(x => 1 == 1)
                .WhereIf(input.projectid != 0, x => x.ProjectId == input.projectid)
                .WhereIf(input.serviceid != 0, x => x.ServiceId == input.serviceid)
                .WhereIf(input.state != RunState.unknow, x => x.StateCode == input.state)
                .WhereIf(input.modelid != 0, x => x.ModelId == input.modelid);

            datalist.TotalCount = await query.CountAsync();

            var list = await (from app in query
                              join b in _dbContext.ModelInfo on app.ModelId equals b.Id into abc
                              from model in abc.DefaultIfEmpty()
                              join c in _dbContext.ServiceInfo on app.ServiceId equals c.Id into aaa
                              from service in aaa.DefaultIfEmpty()
                              join d in _dbContext.ProjectInfo on app.ProjectId equals d.Id into bbb
                              from project in bbb.DefaultIfEmpty()
                              select new
                              {
                                  ProjectName = project.Name,
                                  ServiceCode = service.Code,
                                  Model = model.Code,
                                  RunState = app.StateCode,
                                  Address = app.Address,
                                  Ports = app.OutPort,
                                  Name = app.Name,
                                  AppId = app.AppID,
                                  Id = app.Id,
                                  Create = app.CreateDate
                              }).OrderByDescending(x => x.Id).Page(input.page, input.size).ToListAsync();

            datalist.Items = list;


            return datalist;
        }
      
    }
}
